package cn.hy.service;


import cn.hy.entity.Order;
import cn.hy.enums.OrderStatusEnum;
import cn.hy.events.OrderStatusChangeEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.statemachine.support.StateMachineReactiveLifecycle;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;


@Service
public class OrderStatusMachineService {

    private static final String ERROR_MSG = "订单前置状态错误";

    @Autowired
    private StateMachine<OrderStatusEnum, OrderStatusChangeEvent> orderStatusMachine;

    @Resource(name = "orderStatusMachinePersister")
    private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEvent, Order> persister;

    // 待付款
    // -> 部分支付 部分支付事件
    public synchronized boolean setPayPart(Order order) {
        return handleEvent(OrderStatusChangeEvent.PAY_WAIT_TO_PAY_PART_EVENT, order);
    }


    // 待付款 -> 已支付(待成团) 全部支付，待成团
    // 部分支付 -> 已支付(待成团) 拼团订单支付剩下的一部分
    public synchronized boolean setPayOver(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case PAY_WAIT:
                return handleEvent(OrderStatusChangeEvent.PAY_WAIT_TO_PAY_OVER_EVENT, order);
            case PAY_PART:
                return handleEvent(OrderStatusChangeEvent.PAY_PART_TO_PAY_OVER_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    // 待付款 -> 待发货(待授权) 实体全部付款待发货，虚拟全部付款待授权
    // 部分支付 -> 待发货(待授权) 订单支付剩下的一部分
    // 已支付(待成团) -> 待发货(待授权) 拼团订单拼团成功
    public synchronized boolean setSendWait(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case PAY_WAIT:
                return handleEvent(OrderStatusChangeEvent.PAY_WAIT_TO_SEND_WAIT_EVENT, order);
            case PAY_PART:
                return handleEvent(OrderStatusChangeEvent.PAY_PART_TO_SEND_WAIT_EVENT, order);
            case PAY_OVER:
                return handleEvent(OrderStatusChangeEvent.PAY_OVER_TO_SEND_WAIT_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    // 待发货(待授权) -> 部分发货
    public synchronized boolean setSendPart(Order order) {
        return handleEvent(OrderStatusChangeEvent.SEND_WAIT_TO_SEND_PART_EVENT, order);
    }


    // 待发货(待授权) -> 已发货(全部发货)
    // 部分发货 -> 已发货(全部发货)
    public synchronized boolean setSendOver(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case SEND_WAIT:
                return handleEvent(OrderStatusChangeEvent.SEND_WAIT_TO_SEND_OVER_EVENT, order);
            case SEND_PART:
                return handleEvent(OrderStatusChangeEvent.SEND_PART_TO_SEND_OVER_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    //    待付款 -> 已完成(全部发货) 不需要发货
    //    部分支付 -> 已完成(全部收货) 不需要发货订单支付剩下的一部分
    //    已支付(待成团) -> 已完成(全部收货) 不需要发货的订单拼团成功
    //    已发货(全部发货) -> 已完成(全部收货)
    public synchronized boolean setFinished(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case PAY_WAIT:
                return handleEvent(OrderStatusChangeEvent.PAY_WAIT_TO_FINISHED_EVENT, order);
            case PAY_PART:
                return handleEvent(OrderStatusChangeEvent.PAY_PART_TO_FINISHED_EVENT, order);
            case PAY_OVER:
                return handleEvent(OrderStatusChangeEvent.PAY_OVER_TO_FINISHED_EVENT, order);
            case SEND_OVER:
                return handleEvent(OrderStatusChangeEvent.SEND_OVER_TO_FINISHED_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    // 已支付(待成团) -> 发起售后申请 拼团订单未拼成功发起售后申请
    // 待发货(待授权) -> 发起售后申请
    // 部分发货 -> 发起售后申请
    // 已发货(全部发货) -> 发起售后申请
    // 已完成(全部收货) -> 发起售后申请
    // 部分退款 -> 发起售后申请 再次发起售后申请
    public synchronized boolean setAftermarketApply(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case PAY_OVER:
                return handleEvent(OrderStatusChangeEvent.PAY_OVER_TO_AFTERMARKET_APPLY_EVENT, order);
            case SEND_WAIT:
                return handleEvent(OrderStatusChangeEvent.SEND_WAIT_TO_AFTERMARKET_APPLY_EVENT, order);
            case SEND_PART:
                return handleEvent(OrderStatusChangeEvent.SEND_PART_TO_AFTERMARKET_APPLY_EVENT, order);
            case SEND_OVER:
                return handleEvent(OrderStatusChangeEvent.SEND_OVER_TO_AFTERMARKET_APPLY_EVENT, order);
            case FINISHED:
                return handleEvent(OrderStatusChangeEvent.FINISHED_TO_AFTERMARKET_APPLY_EVENT, order);
            case REFUND_PART:
                return handleEvent(OrderStatusChangeEvent.REFUND_PART_TO_AFTERMARKET_APPLY_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    // 发起售后申请 -> 部分退款
    public synchronized boolean setRefundPart(Order order) {
        return handleEvent(OrderStatusChangeEvent.AFTERMARKET_APPLY_TO_REFUND_PART_EVENT, order);
    }


    // 待付款 -> 已关闭 订单取消
    // 发起售后申请 -> 已关闭
    // 部分退款 -> 已关闭
    public synchronized boolean setClosed(Order order) {
        OrderStatusEnum orderStatusEnum = getPrefixStatus(order);
        switch (orderStatusEnum) {
            case PAY_WAIT:
                return handleEvent(OrderStatusChangeEvent.PAY_WAIT_TO_CLOSED_EVENT, order);
            case AFTERMARKET_APPLY:
                return handleEvent(OrderStatusChangeEvent.AFTERMARKET_APPLY_TO_CLOSED_EVENT, order);
            case REFUND_PART:
                return handleEvent(OrderStatusChangeEvent.REFUND_PART_TO_CLOSED_EVENT, order);
            default:
                throw new RuntimeException(ERROR_MSG);
        }
    }


    /**
     * @param event:
     * @param order:
     * @Description: 发送订单状态转换事件
     **/
    private synchronized boolean sendEvent(OrderStatusChangeEvent event, Order order) {
        boolean result = false;
        try {
            Message<OrderStatusChangeEvent> message = MessageBuilder.withPayload(event).setHeader("order", order).build();
            orderStatusMachine.start();
            // 尝试恢复状态机状态
            persister.restore(orderStatusMachine, order);
            result = orderStatusMachine.sendEvent(message);
            // 持久化状态机状态
            persister.persist(orderStatusMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            orderStatusMachine.stop();
        }
        return result;
    }


    private boolean handleEvent(OrderStatusChangeEvent event, Order order) {
        if (!sendEvent(event, order)) {
            throw new RuntimeException("订单状态流转事件失败");
        }
        return true;
    }

    // 获取订单的前置状态
    private OrderStatusEnum getPrefixStatus(Order order) {
        OrderStatusEnum orderStatusEnum = OrderStatusEnum.getByCode(order.getStatus());
        if (Objects.isNull(orderStatusEnum)) {
            throw new RuntimeException("获取订单前置状态失败");
        }
        return orderStatusEnum;
    }

}
